package cn.iphone.NPlayer.service.impl;

import cn.iphone.NPlayer.constants.RedisSmsConstants;
import cn.iphone.NPlayer.domain.MessageSms;
import cn.iphone.NPlayer.dto.RedisSmsDto;
import cn.iphone.NPlayer.dto.SmsCodeDto;
import cn.iphone.NPlayer.exception.GlobalException;
import cn.iphone.NPlayer.exception.GlobalExceptionCodeEnum;
import cn.iphone.NPlayer.properties.SmsRegisterProperties;
import cn.iphone.NPlayer.service.IMessageSmsService;
import cn.iphone.NPlayer.service.IVerifyCodeService;
import cn.iphone.NPlayer.util.AssertUtil;
import cn.iphone.NPlayer.util.StrUtils;
import cn.iphone.NPlayer.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 验证码业务
 * @author ikun
 */
@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private IMessageSmsService messageSmsService;
    @Autowired
    private SmsRegisterProperties smsRegisterProperties;

    @Override
    public String imageCodeKey(String imageCodeKey) {
        // 工具类生产图形验证码
        String code = StrUtils.getComplexRandomString(4);
        // 注入RedisTemplate，保存,过期时间为5分钟
        redisTemplate.opsForValue().set(imageCodeKey,code,5, TimeUnit.MINUTES);
        // 使用工具类生成图形验证码编码之后的base64的字符串
        return VerifyCodeUtils.verifyCode(110, 40, code);
    }

//    @Override
//    public void sendSmsCode(SmsCodeDto smsCodeDto) {
//        String phone = smsCodeDto.getPhone();
//        String imageCode = smsCodeDto.getImageCode();
//        String imageCodeKey = smsCodeDto.getImageCodeKey();
//        Date date = new Date();
//        if (StringUtils.isEmpty(phone)){
//            throw new GlobalException();
//        }
//        if (StringUtils.isEmpty(imageCode)){
//            throw new GlobalException();
//        }
//        if (StringUtils.isEmpty(imageCodeKey)){
//            throw new GlobalException();
//        }
//        // 2. 校验图形验证码是否过期、正确
//        Object object = redisTemplate.opsForValue().get(imageCodeKey);
//        if (object == null) {
//            throw new GlobalException("图形验证码过期，请重新获取");
//        }
//        if (!object.toString().equalsIgnoreCase(imageCode)) {
//            throw new GlobalException("图形验证码错误");
//        }
//        // 2.拼接业务键，从Redis中获取code
//        String redisKey = "register:" + phone;
//        Object o = redisTemplate.opsForValue().get(redisKey);
//        // 3.判断code是否存在  9527:时间戳
//        String code = null;
//        if (o != null){
//            // 1.存在
//            String[] split = o.toString().split(":");
//            if (date.getTime() - Long.valueOf(split[1]) > 60 * 1000 ){ // 大于60秒说明用户可以重发
//                code = split[0];
//            }else { // 小于60，不让重发，抛出业务异常
//                throw new GlobalException(GlobalExceptionCodeEnum.COMMON_INTERVAL_ERROR);
//            }
//        }else {
//            // 2.不存在
//            code = StrUtils.getRandomString(4);
//        }
//        // 4.将code拼接时间戳，存入redis
//        String smsRedisValue = code + ":" + date.getTime();
//        redisTemplate.opsForValue().set(redisKey, smsRedisValue, 5 * 60 * 1000, TimeUnit.MILLISECONDS);
//        // 5.存储短信验证码到数据库
//        MessageSms messageSms = new MessageSms();
//        messageSms.setTitle("注册验证码");
//        messageSms.setContent("您的验证码为 "+code+" ,请在 5 分钟内使用");
//        String ip = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRemoteAddr();
//        messageSms.setIp(ip);
//        messageSms.setSendTime(date);
//        messageSmsService.insert(messageSms);
//        //6.发送短信验证码
//        log.info("您的短信验证码为：{}", code);
//    }

    /**
     * 高级写法
     */
    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto) {
        String phone = smsCodeDto.getPhone();
        String imageCode = smsCodeDto.getImageCode();
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        Date date = new Date();
        // 0.JSR303

        // 1. 校验图形验证码是否过期、正确
        Object redisImageCode = redisTemplate.opsForValue().get(imageCodeKey);
        AssertUtil.isNotNull(redisImageCode,GlobalExceptionCodeEnum.IMAGECODE_ERROR);
        AssertUtil.isEqualsIgnoreCase((String) redisImageCode,imageCode,GlobalExceptionCodeEnum.IMAGECODE_ERROR);
        // 2.拼接业务键，从Redis中获取code
        String redisKey = String.format(RedisSmsConstants.REDIS_REGISTER_PHONE_KEY, phone);
        Object o = redisTemplate.opsForValue().get(redisKey);
        // 3.判断code是否存在  1111:时间戳
        String code = null;
        if (o != null){
            // 1.获取到value的时间戳
            RedisSmsDto redisSmsDto = (RedisSmsDto)o;
            // 2.判断是否过了一分钟，如果没过，就提示用户操作频繁
            boolean boo = (date.getTime() - redisSmsDto.getTime() < smsRegisterProperties.getInterval());
            AssertUtil.isFalse(boo,GlobalExceptionCodeEnum.COMMON_INTERVAL_ERROR);
            // 3.如果超过了一分钟，就用之前的code
            code = redisSmsDto.getCode();
        }else {
            // 2.不存在
            code = StrUtils.getRandomString(smsRegisterProperties.getCodesize());
        }
        // 4.将code拼接时间戳，存入redis
        RedisSmsDto redisSmsDto = new RedisSmsDto(code, date.getTime());
        redisTemplate.opsForValue().set(redisKey, redisSmsDto, smsRegisterProperties.getExpiredtime(), TimeUnit.MILLISECONDS);
        // 5.存储短信验证码到数据库
        sendSmsMessageAndSaveMessageSms(date, code);
    }

    private void sendSmsMessageAndSaveMessageSms(Date date, String code) {
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(smsRegisterProperties.getTitle());
        String content = String.format(smsRegisterProperties.getContent(), code);
        messageSms.setContent(content);
        String ip = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRemoteAddr();
        messageSms.setIp(ip);
        messageSms.setSendTime(date);
        messageSmsService.insert(messageSms);
        //6.发送短信验证码
        log.info(content);
    }
}
